#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PATHNAME "./"
#define PROJID 160

const int default_fd = -1;
const int default_size = 1024;
// 获取已经存在的消队列
#define GET_MSGQUEUE (IPC_CREAT)
// 创建新的消息队列
#define CREATE_MSGQUEUE (IPC_CREAT | IPC_EXCL | 0666)
class MsgQueue
{
    // 有类型的数据块
    struct msgbuf
    {
        long mtype;
        char mtext[default_size];
    };

public:
    MsgQueue() : _msgfd(default_fd) {}
    // 创建消息队列
    void Create(int flag)
    {
        // 获取唯一键值
        key_t key = ftok(PATHNAME, PROJID);
        if (key == -1)
        {
            std::cout << "ftok error" << std::endl;
            exit(1);
        }
        // 创建消息队列 --- 暂定
        _msgfd = msgget(key, flag);
        if (_msgfd == -1)
        {
            std::cout << "msgget error" << std::endl;
            exit(2);
        }
        std::cout << "msgqueue create success: " << _msgfd << std::endl;
    }
    // 发送消息
    void Send(int type, const std::string &data)
    {
        struct msgbuf msg;
        memset(&msg, 0, sizeof(msg));
        msg.mtype = type;
        memcpy(msg.mtext, data.c_str(), default_size);
        // 注意：不能填写成sizeof(msg), 我们需要填入纯文本的长度
        int n = msgsnd(_msgfd, &msg, sizeof(msg.mtext), 0);
        if (n == -1)
        {
            std::cout << "msgsnd error" << std::endl;
            return;
        }
        std::cout << "send msg success: " << data << std::endl;
    }
    // 接收消息, data是输出型参数
    void Recv(int type, std::string &data)
    {
        struct msgbuf msg;
        int n = msgrcv(_msgfd, &msg, sizeof(msg.mtext), type, 0);
        if (n == -1)
        {
            std::cout << "msgrcv error" << std::endl;
            return;
        }
        msg.mtext[n] = '\0';
        data = msg.mtext;
    }
    // 获取消息队列中的属性
    void GetAttr()
    {
        struct msqid_ds outbuffer;
        int n = msgctl(_msgfd, IPC_STAT, &outbuffer);
        if (n == -1)
        {
            std::cout << "msgctl error" << std::endl;
            return;
        }
        std::cout << "msgqueue attr: " << std::hex << outbuffer.msg_perm.__key << std::endl;
    }
    // 删除消息队列
    void Destroy()
    {
        int n = msgctl(_msgfd, IPC_RMID, 0);
        if (n == -1)
        {
            std::cout << "msgctl error" << std::endl;
            exit(3);
        }
        std::cout << "msgqueue destroy success: " << _msgfd << std::endl;
    }
    ~MsgQueue() {}

private:
    int _msgfd;
};

// 我们需要定义消息类型
#define MSG_TYPE_CLIENT 1
#define MSG_TYPE_SERVER 2

class Server : public MsgQueue
{
public:
    Server()
    {
        MsgQueue::Create(CREATE_MSGQUEUE);
        std::cout << "server create msgqueue success" << std::endl;
    }
    ~Server()
    {
        MsgQueue::Destroy();
    }

private:
};

class Client : public MsgQueue
{
public:
    Client()
    {
        MsgQueue::Create(GET_MSGQUEUE);
        std::cout << "cliente get msgqueue success" << std::endl;
    }
    ~Client()
    {
    }

private:
};